/*
 * Copyright (C) 2011 Nicolas BARBOTIN
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

//#define NMI_DISABLE_CONVERT

#include <SDL/SDL.h>
#include <iostream>
#include "NMI.h"
#include "FX.h"
#include "GUI.h"

#define SDL_main main
#define KDL_COUNT "3" //The Last Level Id

SDL_Surface *tiles[11];
unsigned int level[8][8];
unsigned int temp_level[8][8];
GUI_DraggableObject arrows[16];
int aslots[4]; //Arrow Slots

enum KTD_TILE_TYPE {
    KTD_NONE,
    KTD_PATH,
    KTD_KEY,
    KTD_LOCK,
    KTD_ICE,
    KTD_ICE_BREAKED,
    KTD_TELEPORT,
    KTD_TELEPORT_ORANGE,
    KTD_TURN_UP,
    KTD_TURN_RIGHT,
    KTD_TURN_DOWN,
    KTD_TURN_LEFT,
    KTD_ENTITY
};

enum KTD_DIRECTION {
    KTD_UP,
    KTD_RIGHT,
    KTD_DOWN,
    KTD_LEFT
};

/* Draw Functions */
void DrawTile(SDL_Surface *screen, int x, int y, KTD_TILE_TYPE tile); //Draw a tile on screen at postion x, y
void KTDDraw(GUI_Button playBtn, GUI_Button stopBtn, SDL_Surface* screen, SDL_Event event); //Main Draw Function

/* Utils */
SDL_Surface *CombineSurfaces(SDL_Surface *bg, SDL_Surface *fg); //Combine two 64x64 surfaces (bg = background, fg = forderground
SDL_Surface *NumberToSurface(SDL_Surface **numbers, const char *num); //Make a number surface with a number map

/* Level Functions */
KTD_TILE_TYPE LevelTile(int x, int y); //Get the tile type at position x, y
void ReadKDL(const char *file); //Read an level file and put it in level[8][8] bi-dimesional array
void PushLevel(); //Temporary Save the level
void PopLevel(); //Restore the "temporary saved level"
SDL_Rect ScanLevelForTeleport(int ix, int iy); //Scan the level for any teleport, ingoring teleport at position ix, iy
SDL_Rect ScanLevelForTeleport2(int ix, int iy); //Same function, but for orange teleports

/* Arrows Funtions */
void SetupArrows(); //Create all arrows surfaces in arrows[16] array
void SetArrowDirection(KTD_DIRECTION dir, int index); //Change arrow direction (must be in one of the 4 slots)
void MoveArrow(int index); //Add one pixel depending the direction for arrow "index"
void SetArrowHasKey(bool hasKey, int index); //Set if arrow "index" has a key (for all directions)
KTD_TILE_TYPE TileUnderArrow(int index); //Return the tile type under arrow "index"
KTD_DIRECTION ArrowDirection(int index);  //Return the direction of arrow "index"
bool ArrowPathEndWithKey(int index); //Checks if arrow "index" is on a lock and has a key. Return true if slot "index" equals -1
bool CheckArrowCollision(int index); //Checks if the is an arrow opposite the arrow "index". Return true if there isn't any or if slot "index" equals -1

int main(int argc, char *argv[])
{
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Surface *screen = SDL_SetVideoMode(640, 512, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
    SDL_WM_SetCaption("Key To Door", NULL);

    aslots[0] = -1;
    aslots[1] = -1;
    aslots[2] = -1;
    aslots[3] = -1;

    tiles[0] = lireImage("images/path.nmi");
    tiles[1] = lireImage("images/key.nmi");
    tiles[2] = lireImage("images/lock.nmi");
    tiles[3] = lireImage("images/ice.nmi");
    tiles[4] = lireImage("images/teleport.nmi");
    tiles[5] = CombineSurfaces(tiles[0], retournerSurface(lireImage("images/turn.nmi"), NMIA_270));
    tiles[6] = CombineSurfaces(tiles[0], lireImage("images/turn.nmi"));
    tiles[7] = CombineSurfaces(tiles[0], retournerSurface(lireImage("images/turn.nmi")));
    tiles[8] = CombineSurfaces(tiles[0], retournerSurface(lireImage("images/turn.nmi"), NMIA_180));
    tiles[9] = lireImage("images/ice_breaked.nmi");
    tiles[10] = lireImage("images/teleport_orange.nmi");

    char *levelId = "0";
    if(argc >= 3) {
        if(strcmp(argv[1], "--load-level ") != 0) {
            sprintf(levelId, "%s", argv[2]);
            std::cout << "\"--load-level\" parameter given. Loading level " << levelId << " !" << std::endl;
        }
    }
    char levelFile[19];
    sprintf(levelFile, "levels/level%s.kdl", levelId);
    SDL_Surface *sidebar = lireImage("images/sidebar.nmi");
    SDL_Surface *string1 = lireImage("images/level.nmi");
    SDL_Surface **nummap = lireMap("images/numbers.nmi", 16, 0, 0, 0);
    SDL_Surface *string2 = NumberToSurface(nummap, levelId);
    SDL_Surface *string3 = lireImage("images/nextlevel.nmi");
    SDL_Surface *string4 = lireImage("images/copyright.nmi");

    GUI_GFX playGFX;
    playGFX.gfx_normal = lireImage("images/play.nmi");
    playGFX.gfx_over = lireImage("images/play_over.nmi");
    playGFX.gfx_pressed = lireImage("images/play_pressed.nmi");
    playGFX.gfx_disabled = lireImage("images/play_disabled.nmi");

    GUI_GFX stopGFX;
    stopGFX.gfx_normal = lireImage("images/stop.nmi");
    stopGFX.gfx_over = lireImage("images/stop_over.nmi");
    stopGFX.gfx_pressed = lireImage("images/stop_pressed.nmi");
    stopGFX.gfx_disabled = lireImage("images/stop_disabled.nmi");

    GUI_Button stopBtn = GUI_CreateButton(0, 320, stopGFX);
    GUI_Button playBtn = GUI_CreateButton(0, 256, playGFX);
    SetupArrows();

    stopBtn.state = GUIS_Disabled;

    SDL_Rect pos_string1;
    pos_string1.x = 0;
    pos_string1.y = 390;

    SDL_Rect pos_string2;
    pos_string2.y = 408;

    SDL_Rect pos_string3;
    pos_string3.x = (screen->w - string3->w) / 2;
    pos_string3.y = (screen->h - string3->h) / 2;

    SDL_Rect pos_string4;
    pos_string4.x = 0;
    pos_string4.y = screen->h - string4->h;

    ReadKDL(levelFile);
    bool quit = false, playing = false, win = false;

    SDL_Event event;
    while(!quit) {
        SDL_WaitEvent(&event);

        if(event.type == SDL_QUIT)
            quit = true;

        SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
        for(int i = 0; i < 4; i++) {
            SDL_Rect sb_pos;
            sb_pos.x = 0;
            sb_pos.y = i * 64;

            SDL_BlitSurface(sidebar, NULL, screen, &sb_pos);
        }

        SDL_BlitSurface(string1, NULL, screen, &pos_string1);
        pos_string2.x = (string1->w - string2->w) / 2;
        SDL_BlitSurface(string2, NULL, screen, &pos_string2);
        SDL_BlitSurface(string4, NULL, screen, &pos_string4);

        GUI_Update(&playBtn, event);

        if(playBtn.clicked) {
            playBtn.state = GUIS_Disabled;
            stopBtn.state = GUIS_Normal;

            for(int i = 0; i < 4; i++)
                if(aslots[i] != -1)
                    arrows[aslots[i]].state = GUIS_Disabled;

            playing = true;
        }

        if(playing) {
            PushLevel();
            for(int i = 0; i < 4; i++) {
                if(i != -1) {
                    arrows[aslots[i]].origin2 = arrows[aslots[i]].position;
                }
            }
        }

        while(playing) {
            for(int i = 0; i < 4; i++) {
                KTD_TILE_TYPE tile = TileUnderArrow(i);

                if(tile == KTD_TURN_UP)
                    SetArrowDirection(KTD_UP, i);

                if(tile == KTD_TURN_RIGHT)
                    SetArrowDirection(KTD_RIGHT, i);

                if(tile == KTD_TURN_DOWN)
                    SetArrowDirection(KTD_DOWN, i);

                if(tile == KTD_TURN_LEFT)
                    SetArrowDirection(KTD_LEFT, i);

                if(tile == KTD_KEY && !arrows[aslots[i]].hasKey) {
                    level[arrows[aslots[i]].position.y / 64][(arrows[aslots[i]].position.x - 128) / 64] = 1;
                    SetArrowHasKey(true, i);
                }

                if(tile == KTD_TELEPORT) {
                    SDL_Rect tpos = ScanLevelForTeleport((arrows[aslots[i]].position.x - 128) / 64, arrows[aslots[i]].position.y / 64);
                    arrows[aslots[i]].position.x = tpos.x * 64 + 128;
                    arrows[aslots[i]].position.y = tpos.y * 64;
                }

                if(tile == KTD_TELEPORT_ORANGE) {
                    SDL_Rect tpos = ScanLevelForTeleport2((arrows[aslots[i]].position.x - 128) / 64, arrows[aslots[i]].position.y / 64);
                    arrows[aslots[i]].position.x = tpos.x * 64 + 128;
                    arrows[aslots[i]].position.y = tpos.y * 64;
                }

                if(tile == KTD_ICE_BREAKED) {
                    level[arrows[aslots[i]].position.y / 64][(arrows[aslots[i]].position.x - 128) / 64] = 0;
                    tile = KTD_NONE;
                }

                if(tile == KTD_ICE) {
                    level[arrows[aslots[i]].position.y / 64][(arrows[aslots[i]].position.x - 128) / 64] = 10;
                }

                if(tile != KTD_NONE && tile != KTD_LOCK && CheckArrowCollision(i))
                    MoveArrow(i);
            }

            if(ArrowPathEndWithKey(0) && ArrowPathEndWithKey(1) && ArrowPathEndWithKey(2) && ArrowPathEndWithKey(3)) {
                for(int i = 0; i < 4; i++) {
                    if(aslots[i] != -1) {
                        arrows[aslots[i]].state = GUIS_Normal;
                        SetArrowHasKey(false, i);
                    }
                    arrows[aslots[i]].position = arrows[aslots[i]].origin;
                    aslots[i] = -1;
                }

                stopBtn.state = GUIS_Disabled;
                playing = false;
                win = true;
            }

            SDL_PollEvent(&event);
            if(event.type == SDL_QUIT) {
                playing = false;
                quit = true;
            }
            GUI_Update(&stopBtn, event);

            if(stopBtn.clicked) {
                stopBtn.state = GUIS_Disabled;
                playBtn.state = GUIS_Normal;
                PopLevel();

                for(int i = 0; i < 4; i++) {
                    if(aslots[i] != -1) {
                        arrows[aslots[i]].state = GUIS_Normal;
                        arrows[aslots[i]].position = arrows[aslots[i]].origin2;
                        SetArrowHasKey(false, i);
                    }
                }

                playing = false;
            }

            KTDDraw(playBtn, stopBtn, screen, event);

            SDL_Flip(screen);
            SDL_Delay(10);
        }

        if(win) {
            int levelNum;
            sscanf(levelId, "%d", &levelNum); //Put the current level ID (char*) to levelNum (int)

            if(strcmp(levelId, KDL_COUNT) != 0) {
                levelNum++; //If exist, goto next level
            } else {
                levelNum = 0; //Else return to start
            }

            levelId = ""; //Reset
            sprintf(levelId, "%d", levelNum);  //Put the new level ID (levelNum, int) to levelId (char*)
            string2 = NumberToSurface(nummap, levelId); //Update the level ID string
            sprintf(levelFile, "levels/level%s.kdl", levelId); //Set the new filename
            ReadKDL(levelFile); //Read level


            bool animation = true;
            SDL_Rect shadow;
            shadow.x = 0;
            shadow.y = 0;
            shadow.w = screen->w;
            shadow.h = screen->h;

            int cr = 85, cv = 85, cb = 85;

            while(animation) {
                SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, cr, cv, cb));
                SDL_FillRect(screen, &shadow, SDL_MapRGB(screen->format, 0, 0, 0));
                SDL_BlitSurface(string3, NULL, screen, &pos_string3);

                SDL_Flip(screen);
                if(shadow.y == screen->h)
                    animation = false;
                else {
                    shadow.y++;
                    pos_string3.y++;
                    if(cr != 255)
                        cr++;
                    else if(cv != 255)
                        cv++;
                    else if(cb != 255)
                        cb++;
                }
            }

            playBtn.state = GUIS_Normal;
            pos_string3.y = (screen->h - string3->h) / 2;

            SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
            for(int i = 0; i < 4; i++) {
                SDL_Rect sb_pos;
                sb_pos.x = 0;
                sb_pos.y = i * 64;

                SDL_BlitSurface(sidebar, NULL, screen, &sb_pos);
            }

            SDL_BlitSurface(string1, NULL, screen, &pos_string1);
            pos_string2.x = (string1->w - string2->w) / 2;
            SDL_BlitSurface(string2, NULL, screen, &pos_string2);
            SDL_BlitSurface(string4, NULL, screen, &pos_string4);

            win = false;
        }

        KTDDraw(playBtn, stopBtn, screen, event);
        SDL_Flip(screen);
    }

    free(nummap);
    return EXIT_SUCCESS;
}

void KTDDraw(GUI_Button playBtn, GUI_Button stopBtn, SDL_Surface *screen, SDL_Event event) {
    SDL_Rect clearArea;
    clearArea.x = 128;
    clearArea.y = 0;
    clearArea.w = screen->w;
    clearArea.h = screen->h;

    SDL_FillRect(screen, &clearArea, SDL_MapRGB(screen->format, 0, 0, 0));

    for(int y = 0; y < 8; y++) {
        for(int x = 0; x < 8; x++) {
            DrawTile(screen, x, y, LevelTile(x, y));
        }
    }

    GUI_Draw(playBtn, screen);
    GUI_Draw(stopBtn, screen);

    for(int i = 0; i < 4; i++) {
        if(aslots[i] != -1) {
            GUI_Update(&arrows[aslots[i]], event);
            GUI_Draw(arrows[aslots[i]], screen);
        }
    }
}

void DrawTile(SDL_Surface *screen, int x, int y, KTD_TILE_TYPE tile) {
    SDL_Rect pos;
    pos.x = 128 + x * 64;
    pos.y = y * 64;

    switch(tile) {
        case KTD_NONE:
            return;
            break;

        case KTD_PATH:
            SDL_BlitSurface(tiles[0], NULL, screen, &pos);
            return;
            break;

        case KTD_KEY:
            SDL_BlitSurface(tiles[1], NULL, screen, &pos);
            return;
            break;

        case KTD_LOCK:
            SDL_BlitSurface(tiles[2], NULL, screen, &pos);
            return;
            break;

        case KTD_ICE:
            SDL_BlitSurface(tiles[3], NULL, screen, &pos);
            return;
            break;

        case KTD_ICE_BREAKED:
            SDL_BlitSurface(tiles[9], NULL, screen, &pos);
            return;
            break;

        case KTD_TURN_UP:
            SDL_BlitSurface(tiles[5], NULL, screen, &pos);
            return;
            break;

        case KTD_TURN_RIGHT:
            SDL_BlitSurface(tiles[6], NULL, screen, &pos);
            return;
            break;

        case KTD_TURN_DOWN:
            SDL_BlitSurface(tiles[7], NULL, screen, &pos);
            return;
            break;

        case KTD_TURN_LEFT:
            SDL_BlitSurface(tiles[8], NULL, screen, &pos);
            return;
            break;

        case KTD_TELEPORT:
            SDL_BlitSurface(tiles[4], NULL, screen, &pos);
            return;
            break;

        case KTD_TELEPORT_ORANGE:
            SDL_BlitSurface(tiles[10], NULL, screen, &pos);
            return;
            break;
    }
}

KTD_TILE_TYPE LevelTile(int x, int y) {
    unsigned int tile = level[y][x];

    if(tile == 0)
        return KTD_NONE;

    if(tile == 1)
        return KTD_PATH;

    if(tile == 2)
        return KTD_KEY;

    if(tile == 3)
        return KTD_LOCK;

    if(tile == 4)
        return KTD_ICE;

    if(tile == 5)
        return KTD_TELEPORT;

    if(tile == 6)
        return KTD_TURN_UP;

    if(tile == 7)
        return KTD_TURN_RIGHT;

    if(tile == 8)
        return KTD_TURN_DOWN;

    if(tile == 9)
        return KTD_TURN_LEFT;

    if(tile == 10)
        return KTD_ICE_BREAKED;

    if(tile == 11)
        return KTD_TELEPORT_ORANGE;

    return KTD_NONE;
}

SDL_Surface *NumberToSurface(SDL_Surface **numbers, const char *num) {
    const int size = numbers[0]->w;

    SDL_Surface *ret = SDL_CreateRGBSurface(SDL_HWSURFACE, size * strlen(num), size, 32, 0, 0, 0, 0);
    SDL_Rect pos;
    pos.y = 0;

    for(int i = 0; i < strlen(num); i++) {
        if(num[i] == '0') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[0], NULL, ret, &pos);
        }

        if(num[i] == '1') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[1], NULL, ret, &pos);
        }

        if(num[i] == '2') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[2], NULL, ret, &pos);
        }

        if(num[i] == '3') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[3], NULL, ret, &pos);
        }

        if(num[i] == '4') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[4], NULL, ret, &pos);
        }

        if(num[i] == '5') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[5], NULL, ret, &pos);
        }

        if(num[i] == '6') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[6], NULL, ret, &pos);
        }

        if(num[i] == '7') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[7], NULL, ret, &pos);
        }

        if(num[i] == '8') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[8], NULL, ret, &pos);
        }

        if(num[i] == '9') {
            pos.x = size * i;
            SDL_BlitSurface(numbers[9], NULL, ret, &pos);
        }
    }

    return ret;
}

void ReadKDL(const char *file) {
    FILE *f = fopen(file, "r");

    for(int i = 0; i < 16; i++)
        free(arrows[i].dropAreas);

    SDL_Rect *areas = (SDL_Rect*) malloc(sizeof(SDL_Rect) * 62);
    int areasCount = 0;

    for(int i = 0; i < 8; i++) {
            fscanf(f, "%d,%d,%d,%d,%d,%d,%d,%d\n", &level[i][0], &level[i][1], &level[i][2], &level[i][3], &level[i][4], &level[i][5], &level[i][6], &level[i][7]);

            for(int j = 0; j < 8; j++) {
                if(level[i][j] == 1) {
                    areas[areasCount].x = j * 64 + 128;
                    areas[areasCount].y = i * 64;
                    areas[areasCount].h = 64;
                    areas[areasCount].w = 64;

                    areasCount++;
                }
            }
    }

    for(int i = 0; i < 16; i++) {
       arrows[i].dropAreas = areas;
       arrows[i].dropAreasCount = areasCount;
   }

    char dir;
    for(int cslot = 0; cslot < 4; cslot++) {
        dir = fgetc(f);

        if(dir == 'h')
            aslots[cslot] = cslot * 4;

        if(dir == 'd')
            aslots[cslot] = cslot * 4 + 1;

        if(dir == 'b')
            aslots[cslot] = cslot * 4 + 2;

        if(dir == 'g')
            aslots[cslot] = cslot * 4 + 3;

        arrows[aslots[cslot]].position.y = cslot * 64;
        arrows[aslots[cslot]].origin.y = cslot * 64;
    }

    fclose(f);
}

void SetupArrows() {
    SDL_Rect *areas = (SDL_Rect*) malloc(sizeof(SDL_Rect));
    GUI_GFX arrows_gfx;

    //Blue color

    arrows_gfx.gfx_normal = lireImage("images/arrow.nmi");
    arrows_gfx.gfx_over = lireImage("images/arrow.nmi");
    arrows_gfx.gfx_pressed = lireImage("images/arrow.nmi");
    arrows_gfx.gfx_disabled = lireImage("images/arrow.nmi");

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[0] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow.nmi"));
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow.nmi"));
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow.nmi"));
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow.nmi"));

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[1] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow.nmi"), NMIA_180);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow.nmi"), NMIA_180);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow.nmi"), NMIA_180);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow.nmi"), NMIA_180);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[2] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow.nmi"), NMIA_270);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow.nmi"), NMIA_270);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow.nmi"), NMIA_270);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow.nmi"), NMIA_270);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[3] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    //Red color

    arrows_gfx.gfx_normal = lireImage("images/arrow_red.nmi");
    arrows_gfx.gfx_over = lireImage("images/arrow_red.nmi");
    arrows_gfx.gfx_pressed = lireImage("images/arrow_red.nmi");
    arrows_gfx.gfx_disabled = lireImage("images/arrow_red.nmi");

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[4] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_red.nmi"));
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_red.nmi"));
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_red.nmi"));
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_red.nmi"));

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[5] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_180);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_180);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_180);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_180);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[6] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_270);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_270);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_270);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_red.nmi"), NMIA_270);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[7] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    //Green Color

    arrows_gfx.gfx_normal = lireImage("images/arrow_green.nmi");
    arrows_gfx.gfx_over = lireImage("images/arrow_green.nmi");
    arrows_gfx.gfx_pressed = lireImage("images/arrow_green.nmi");
    arrows_gfx.gfx_disabled = lireImage("images/arrow_green.nmi");

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[8] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_green.nmi"));
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_green.nmi"));
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_green.nmi"));
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_green.nmi"));

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[9] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_180);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_180);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_180);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_180);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[10] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_270);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_270);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_270);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_green.nmi"), NMIA_270);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[11] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    //Yellow Color

    arrows_gfx.gfx_normal = lireImage("images/arrow_yellow.nmi");
    arrows_gfx.gfx_over = lireImage("images/arrow_yellow.nmi");
    arrows_gfx.gfx_pressed = lireImage("images/arrow_yellow.nmi");
    arrows_gfx.gfx_disabled = lireImage("images/arrow_yellow.nmi");

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[12] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_yellow.nmi"));
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_yellow.nmi"));
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_yellow.nmi"));
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_yellow.nmi"));

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[13] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_180);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_180);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_180);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_180);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[14] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);

    arrows_gfx.gfx_normal = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_270);
    arrows_gfx.gfx_over = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_270);
    arrows_gfx.gfx_pressed = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_270);
    arrows_gfx.gfx_disabled = retournerSurface(lireImage("images/arrow_yellow.nmi"), NMIA_270);

    SDL_SetColorKey(arrows_gfx.gfx_disabled, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_disabled->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_normal, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_normal->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_over, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_over->format, 0, 0, 0));
    SDL_SetColorKey(arrows_gfx.gfx_pressed, SDL_SRCCOLORKEY, SDL_MapRGB(arrows_gfx.gfx_pressed->format, 0, 0, 0));
    arrows[15] = GUI_CreateDraggable(0, 0, arrows_gfx, true, areas, 0);
}

KTD_TILE_TYPE TileUnderArrow(int index) {
    SDL_Rect pos = arrows[aslots[index]].position;

    if(pos.x >= 128 && pos.x % 64 == 0 && pos.y % 64 == 0) { //If the position is a part of the map (if it's a tile)
        SDL_Rect tilePos;
        tilePos.x = (pos.x - 128) / 64;
        tilePos.y = pos.y / 64;

        return LevelTile(tilePos.x, tilePos.y);
    } else {
        return KTD_ENTITY;
    }
}

KTD_DIRECTION ArrowDirection(int index) {
    for(int i = 0; i < 4; i++) {
        if(aslots[index] == i * 4)
            return KTD_UP;

        if(aslots[index] == i * 4 + 1)
            return KTD_RIGHT;

        if(aslots[index] == i * 4 + 2)
            return KTD_DOWN;

        if(aslots[index] == i * 4 + 3)
            return KTD_LEFT;
    }
}

void SetArrowDirection(KTD_DIRECTION dir, int index) {
    int color = 0;
    for(int i = 0; i < 4; i++) {
        if(aslots[index] >= i * 4 && aslots[index] <= i * 4 + 3) {
            color = i;
            i = 3;
        }
    }

    SDL_Rect cpos;
    cpos.x = arrows[aslots[index]].position.x;
    cpos.y = arrows[aslots[index]].position.y;

    switch(dir) {
        case KTD_UP:
            aslots[index] = color * 4;
            break;

        case KTD_RIGHT:
            aslots[index] = color * 4 + 1;
            break;

        case KTD_DOWN:
            aslots[index] = color * 4 + 2;
            break;

        case KTD_LEFT:
            aslots[index] = color * 4 + 3;
            break;
    }

    arrows[aslots[index]].position.x = cpos.x;
    arrows[aslots[index]].position.y = cpos.y;
}

void PushLevel() {
    for(int y = 0; y < 8; y++) {
        for(int x = 0; x < 8; x++) {
            temp_level[y][x] = level[y][x];
        }
    }
}

void PopLevel() {
    for(int y = 0; y < 8; y++) {
        for(int x = 0; x < 8; x++) {
            level[y][x] = temp_level[y][x];
        }
    }
}

SDL_Rect ScanLevelForTeleport(int ix, int iy) {
    for(int y = 0; y < 8; y++) {
        for(int x = 0; x < 8; x++) {
            if(LevelTile(x, y) == KTD_TELEPORT && x != ix && y != iy) {
                SDL_Rect ret;
                ret.x = x;
                ret.y = y;

                return ret;
            }
        }
    }
}

SDL_Rect ScanLevelForTeleport2(int ix, int iy) {
    for(int y = 0; y < 8; y++) {
        for(int x = 0; x < 8; x++) {
            if(LevelTile(x, y) == KTD_TELEPORT_ORANGE && x != ix && y != iy) {
                SDL_Rect ret;
                ret.x = x;
                ret.y = y;

                return ret;
            }
        }
    }
}


void MoveArrow(int index) {
    if(arrows[aslots[index]].position.x >= 128) {
        switch(ArrowDirection(index)) {
            case KTD_UP:
                arrows[aslots[index]].position.y--;
                break;

            case KTD_RIGHT:
                arrows[aslots[index]].position.x++;
                break;

            case KTD_DOWN:
                arrows[aslots[index]].position.y++;
                break;

            case KTD_LEFT:
                arrows[aslots[index]].position.x--;
        }
    }
}

SDL_Surface *CombineSurfaces(SDL_Surface *bg, SDL_Surface *fg) {
    SDL_Rect pos;
    pos.x = 0;
    pos.y = 0;

    SDL_Surface *ns = SDL_CreateRGBSurface(SDL_HWSURFACE, 64, 64, 32, 0, 0, 0, 0);
    SDL_BlitSurface(bg, NULL, ns, &pos);
    SDL_SetColorKey(fg, SDL_SRCCOLORKEY, SDL_MapRGB(fg->format, 0, 0, 0));

    SDL_BlitSurface(fg, NULL, ns, &pos);
    return ns;
}

void SetArrowHasKey(bool hasKey, int index) {
    int color = 0;
    for(int i = 0; i < 4; i++) {
        if(aslots[index] >= i * 4 && aslots[index] <= i * 4 + 3) {
            color = i;
            i = 3;
        }
    }

    arrows[color * 4].hasKey = hasKey;
    arrows[color * 4 + 1].hasKey = hasKey;
    arrows[color * 4 + 2].hasKey = hasKey;
    arrows[color * 4 + 3].hasKey = hasKey;
}

bool ArrowPathEndWithKey(int index) {
    if(aslots[index] == -1)
        return true;

    if(TileUnderArrow(index) == KTD_LOCK && arrows[aslots[index]].hasKey)
        return true;

    return false;
}

bool CheckArrowCollision(int index) {
    if(aslots[index] == -1)
        return true;

    for(int i = 0; i < 4; i++) {
        if(i != index) {
            if(arrows[aslots[index]].position.x == arrows[aslots[i]].position.x && arrows[aslots[index]].position.y == arrows[aslots[i]].position.y)
                return false;
        }
    }

    return true;
}
